﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using JelleDruyts.Windows;
using Schedulr.Infrastructure;
using Schedulr.Models;

namespace Schedulr.ViewModels
{
    public class AccountViewModel
    {
        #region Fields

        private List<AccountUserMessageViewModel> tempUserMessages;
        private UserInfo tempUserInfo;
        private object updateLock = new object();

        #endregion

        #region Properties

        public ObservableCollection<AccountUserMessageViewModel> UserMessages { get; private set; }
        public Account Account { get; private set; }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="AccountViewModel"/> class.
        /// </summary>
        /// <param name="account">The account.</param>
        public AccountViewModel(Account account)
        {
            this.Account = account;
            this.UserMessages = new ObservableCollection<AccountUserMessageViewModel>();
            this.tempUserMessages = new List<AccountUserMessageViewModel>();
        }

        #endregion

        #region Update

        /// <summary>
        /// Prepares the update.
        /// </summary>
        /// <param name="updatingAccountsTask">The task that tracks updating the accounts.</param>
        public void UpdatePrepare(ApplicationTask updatingAccountsTask)
        {
            lock (updateLock)
            {
                Logger.Log("Retrieving account information for " + this.Account.Name, TraceEventType.Verbose);
                this.tempUserMessages.Clear();
                this.tempUserInfo = null;
                if (!FlickrClient.IsOnline())
                {
                    var message = App.ApplicationName + " couldn't connect to Flickr and is working offline";
                    updatingAccountsTask.Status = message;
                    Logger.Log(message, TraceEventType.Verbose);
                    this.tempUserMessages.Add(new AccountUserMessageViewModel(message));
                    this.tempUserMessages.Add(new AccountUserMessageViewModel("Click here to try again.", new RelayCommand(o => Tasks.UpdateAccount(this))));
                }
                else
                {
                    try
                    {
                        var flickr = new FlickrClient(this.Account.AuthenticationToken);
                        this.tempUserInfo = flickr.GetUserInfo();
                        var status = flickr.GetUserStatus();
                        this.tempUserMessages.Add(new AccountUserMessageViewModel(string.Format(CultureInfo.CurrentCulture, "You've uploaded {0} of your {1} limit this month ({2})", status.BandwidthUsed.ToDisplayString(), status.BandwidthMax.ToDisplayString(), status.BandwidthUsedPercentage.ToPercentageString())));
                        this.tempUserMessages.Add(new AccountUserMessageViewModel(string.Format(CultureInfo.CurrentCulture, "The maximum file size you are allowed to upload is {0}.", tempUserInfo.UploadLimit.ToDisplayString())));
                    }
                    catch (Exception exc)
                    {
                        var errorMessage = "Failed to retrieve the account information for " + this.Account.Name;
                        Logger.Log(errorMessage, exc);
                        updatingAccountsTask.SetError(errorMessage, exc);
                        this.tempUserMessages.Add(new AccountUserMessageViewModel("Failed to retrieve the account information: " + exc.Message));
                        this.tempUserMessages.Add(new AccountUserMessageViewModel("Click here to try again.", new RelayCommand(o => Tasks.UpdateAccount(this))));
                    }
                }
            }
        }

        /// <summary>
        /// Commits the update.
        /// </summary>
        /// <param name="updatingAccountsTask">The task that tracks updating the accounts.</param>
        /// <returns><see langword="true"/> if the update succeeded, <see langword="false"/> otherwise.</returns>
        public bool UpdateCommit(ApplicationTask updatingAccountsTask)
        {
            lock (updateLock)
            {
                Logger.Log("Updating account information for " + this.Account.Name, TraceEventType.Verbose);

                // Update user messages.
                this.UserMessages.Clear();
                this.tempUserMessages.ForEach(m => this.UserMessages.Add(m));

                // Update user information.
                var success = false;
                if (this.tempUserInfo != null)
                {
                    this.Account.UserInfo = tempUserInfo;
                    success = true;
                }

                return success;
            }
        }

        #endregion
    }
}